#include <kutils.h>
#include <string.h>
#include "memory.h"
#include "keyboard.h"
#include "syscall.h"
#include "vfs.h"
#include "display.h"

void kbd_leds_handler(syscall_regs_t *r);
s32int kbd_open_fs(fs_node_t *node);
s32int kbd_close_fs(fs_node_t *node);
s32int kbd_read_fs(fs_node_t *node, u32int offset, u32int size, u8int *buffer);
s32int kbd_create_dev_file(s8int *name);

extern fs_node_t *fs_root;
extern u8int kbd_buffer[512];
extern u32int kbd_buffer_pos;

void kbd_leds_handler(syscall_regs_t *r)
{
	kbd_leds(r->arg1, r->arg2, r->arg3);
	r->success = 1;
}

s32int kbd_open_fs(fs_node_t *node)
{
	if(!node)
		return 0;
	return 1;
}

s32int kbd_close_fs(fs_node_t *node)
{
	if(!node)
		return 0;
	return 1;
}

s32int kbd_read_fs(fs_node_t *node, u32int offset, u32int size, u8int *buffer)
{
	if(!node)
		return 0;

	node->length = kbd_buffer_pos;

	u32int ip = 0;//s32internal position
	//ignore the offset...
	offset = 0;
	//and while neither the s32internal or external positions are overrun...
	while(ip < kbd_buffer_pos)
	{
		if(ip >= size)
			break;

		buffer[ip] = kbd_buffer[ip];
		ip++;
	}

	kbd_clear_buffer();
	return 1;
}

s32int kbd_create_dev_file(s8int *name)
{
	fs_node_t *dev_node = fs_root->first_child;

	if(!dev_node)
		return 0;	

	fs_node_t *new_node = (fs_node_t*)kmalloc(sizeof(fs_node_t));
	strcpy((s8int*)new_node->name,name);
	new_node->length = 0;
	new_node->inode = get_valid_inode();
	new_node->flags = FS_FILE;
	new_node->read = &kbd_read_fs;
   new_node->write = 0;
   new_node->open = &kbd_open_fs;
   new_node->close = &kbd_close_fs;
   new_node->ptr = 0;
	new_node->dvr_num = 0;
	new_node->dvr_ptr = 0;
	new_node->parent = dev_node;//it's parent is the /dev node
	new_node->next_sibling = 0;
	new_node->first_child = 0;

	if(dev_node->first_child == 0)//the dev node has no children at this time
	{
		dev_node->first_child = new_node;
	}
	else//the dev node alredy has atleast one child, let's add this new one to the end of the linked list
	{
		fs_node_t *tmp_node = dev_node->first_child;
		while(tmp_node)
		{
			if(tmp_node->next_sibling)
			{
				tmp_node = tmp_node->next_sibling;
			}
			else
			{
				tmp_node->next_sibling = new_node;
				break;
			}
		}
	}

	return 1;
}

void init_kbd_interface(void)
{
	kbd_create_dev_file("kbd");
	install_syscall(SYS_KBD_LEDS, kbd_leds_handler);
}
